前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket

# koa2简析结构

30 秒速记

  • Application:app.use 把中间件推进数组,app.listen 实际是 http.createServer(app.callback())
  • 每个请求进来,createContext 新建一个 ctx,挂上 request / response 和原生 req / res
  • koa-compose 把中间件数组串成一个函数,dispatch(i) 调第 i 个,next 就是 dispatch(i + 1)
  • 整条链跑完后 respond(ctx) 根据 ctx.body 的类型统一写响应;出错走 ctx.onerror
  • 同一个中间件调两次 next() 会被拦下,报 next() called multiple times

Koa 的源码结构可以浓缩成一句话:app 维护一个中间件数组,每个请求新建一个 ctx,用 compose 把中间件串成洋葱,跑完再统一写响应。 app.listen 本质就是 http.createServer(app.callback()).listen(),callback 里先 compose 好中间件,每来一个请求就 createContext 造一个 ctx,然后执行这条链。中间件里只是给 ctx.body 赋值,真正 res.end 是链条结束后 respond 函数干的,所以外层中间件在 await next() 之后还能改响应内容。抛出的错误沿 Promise 链冒到最外面,没人接就交给 ctx.onerror 返回 500。

理解「koa2简析结构」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 middleware 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

Koa 的核心源码只有几百行,抓住三个函数就能看懂整个流程。

第一个是 use,它就是往数组里推一个函数:

use(fn) {
  this.middleware.push(fn)
  return this
}
@前端进阶之旅: 代码已经复制到剪贴板

第二个是 listen 和 callback。listen 只是 http.createServer(this.callback()).listen(...args) 的简写;callback 先用 koa-compose 把中间件数组合成一个函数,再返回 Node 需要的 (req, res) 处理器:

callback() {
  const fn = compose(this.middleware)
  return (req, res) => {
    const ctx = this.createContext(req, res)   // 每个请求一个新 ctx
    return this.handleRequest(ctx, fn)
  }
}
@前端进阶之旅: 代码已经复制到剪贴板

第三个是 handleRequest,执行中间件链,成功了统一响应,失败了统一处理错误:

handleRequest(ctx, fnMiddleware) {
  ctx.res.statusCode = 404                       // 默认 404,有人设了 body 才会改
  const onerror = err => ctx.onerror(err)
  return fnMiddleware(ctx).then(() => respond(ctx)).catch(onerror)
}
@前端进阶之旅: 代码已经复制到剪贴板

respond 根据 ctx.body 的类型决定怎么写:字符串和 Buffer 直接 res.end,流就 pipe 过去,普通对象 JSON.stringify 后发送。这也是为什么在中间件里只需要给 ctx.body 赋值,不用自己 res.end。

compose 是洋葱模型的来源:dispatch(i) 执行第 i 个中间件,并把 () => dispatch(i + 1) 作为 next 传进去,所以 await next() 就是「等里面所有中间件跑完」,返回后再执行自己剩下的代码。

面试官追问

追问 1为什么 Koa 里外层中间件在 await next() 之后改 ctx.body 还能生效?
参考回答

因为中间件只是改 ctx 上的值,并没有真正发响应。整条链的 Promise 完成之后 respond(ctx) 才读 ctx.body 写到 res,所以最后一次赋值算数。

追问 2ctx.request 和 ctx.req 有什么区别?
参考回答

ctx.req 是 Node 原生的 IncomingMessage,ctx.request 是 Koa 包的一层,提供 query、path、accepts() 这些便捷属性和方法。日常用 ctx.request,直接读原生流(比如自己解析上传)才碰 ctx.req。

追问 3中间件里在成功分支和 finally 里各调了一次 next(),会怎样?
参考回答

第二次调用 compose 会直接 reject,报 next() called multiple times。它靠记录上一次执行到的下标来判断,同一个位置再调就拦下。

追问 4测试时怎么不起端口就测 Koa 应用?
参考回答

app.callback() 返回的就是 (req, res) => {} 处理函数,supertest(app.callback()) 直接发请求,不占端口。

追问 5为什么每个请求都要新建一个 ctx,不能复用吗?
参考回答

ctx 上挂着这次请求的 body、state、status,并发请求共用一个就会互相串数据。每次 Object.create 一个新对象,原型指向 app.context,所以 app.context 上加的属性每个 ctx 都能读到。

# koa2简析结构

# 源码文件

30 秒速记

  • 核心就 lib/ 下四个文件:application.js / context.js / request.js / response.js
  • application.js = 入口:use 收中间件、listen 起服务、callback 组装 compose 并创建 ctx
  • context.js = ctx 的原型:onerror、throw,以及用 delegates 把 request / response 的属性代理过来
  • request.js / response.js = 对原生 req / res 的封装,ctx.query、ctx.body 的真正实现在这
  • 读源码路线:从 application.js 的 listen → callback → handleRequest 顺着往下看

Koa2 的源码核心只有 lib 目录下四个文件,application.js 是入口,另外三个分别管上下文、请求和响应。 application.js 负责收集中间件、创建 ctx、执行中间件链再统一响应;request.js 和 response.js 包了原生 req / res,比如 query 怎么解析、body 赋值后 Content-Type 怎么推断都在这里。context.js 是 ctx 的原型,它本身没多少逻辑,主要是把 request 和 response 上的常用属性代理出来,所以你能直接写 ctx.path、ctx.body。看源码我会从 application.js 的 listen 开始顺着调用往下读,比四个文件挨个看好懂得多。

├── lib
│   ├── application.js
│   ├── context.js
│   ├── request.js
│   └── response.js
└── package.json
@前端进阶之旅: 代码已经复制到剪贴板

这个就是 GitHub https://github.com/koajs/koa上开源的koa2源码的源文件结构,核心代码就是lib目录下的四个文件

  • application.js 是整个koa2 的入口文件,封装了context,request,response,以及最核心的中间件处理流程。
  • context.js 处理应用上下文,里面直接封装部分request.js和response.js的方法
  • request.js 处理http请求
  • response.js 处理http响应

面试官追问

追问 1ctx.body = 'hi' 这行赋值,真正处理逻辑在哪个文件?
参考回答

context.js 只是把 body 代理到 response,真正的 set body() 在 response.js 里,它会顺手把状态码设成 200、根据内容推断 Content-Type。

追问 2ctx.path 为什么能直接用,ctx 上明明没定义这个属性?
参考回答

context.js 用 delegates 库把 request.path 代理到了 ctx 上,读 ctx.path 实际读的是 ctx.request.path。哪些属性被代理了,看 context.js 底部那一串 .access() / .getter() 就清楚。

追问 3想给所有 ctx 加一个 ctx.success(data) 方法,改哪?
参考回答

不用改源码,挂到 app.context 上就行:

基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket
完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

koa2简析结构|Nodejs专题系列

# koa2简析结构

30 秒速记

  • Application:app.use 把中间件推进数组,app.listen 实际是 http.createServer(app.callback())
  • 每个请求进来,createContext 新建一个 ctx,挂上 request / response 和原生 req / res
  • koa-compose 把中间件数组串成一个函数,dispatch(i) 调第 i 个,next 就是 dispatch(i + 1)
  • 整条链跑完后 respond(ctx) 根据 ctx.body 的类型统一写响应;出错走 ctx.onerror
  • 同一个中间件调两次 next() 会被拦下,报 next() called multiple times

Koa 的源码结构可以浓缩成一句话:app 维护一个中间件数组,每个请求新建一个 ctx,用 compose 把中间件串成洋葱,跑完再统一写响应。 app.listen 本质就是 http.createServer(app.callback()).listen(),callback 里先 compose 好中间件,每来一个请求就 createContext 造一个 ctx,然后执行这条链。中间件里只是给 ctx.body 赋值,真正 res.end 是链条结束后 respond 函数干的,所以外层中间件在 await next() 之后还能改响应内容。抛出的错误沿 Promise 链冒到最外面,没人接就交给 ctx.onerror 返回 500。

理解「koa2简析结构」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 middleware 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

Koa 的核心源码只有几百行,抓住三个函数就能看懂整个流程。

第一个是 use,它就是往数组里推一个函数:

use(fn) {
  this.middleware.push(fn)
  return this
}
@前端进阶之旅: 代码已经复制到剪贴板

第二个是 listen 和 callback。listen 只是 http.createServer(this.callback()).listen(...args) 的简写;callback 先用 koa-compose 把中间件数组合成一个函数,再返回 Node 需要的 (req, res) 处理器:

callback() {
  const fn = compose(this.middleware)
  return (req, res) => {
    const ctx = this.createContext(req, res)   // 每个请求一个新 ctx
    return this.handleRequest(ctx, fn)
  }
}
@前端进阶之旅: 代码已经复制到剪贴板

第三个是 handleRequest,执行中间件链,成功了统一响应,失败了统一处理错误:

handleRequest(ctx, fnMiddleware) {
  ctx.res.statusCode = 404                       // 默认 404,有人设了 body 才会改
  const onerror = err => ctx.onerror(err)
  return fnMiddleware(ctx).then(() => respond(ctx)).catch(onerror)
}
@前端进阶之旅: 代码已经复制到剪贴板

respond 根据 ctx.body 的类型决定怎么写:字符串和 Buffer 直接 res.end,流就 pipe 过去,普通对象 JSON.stringify 后发送。这也是为什么在中间件里只需要给 ctx.body 赋值,不用自己 res.end。

compose 是洋葱模型的来源:dispatch(i) 执行第 i 个中间件,并把 () => dispatch(i + 1) 作为 next 传进去,所以 await next() 就是「等里面所有中间件跑完」,返回后再执行自己剩下的代码。

面试官追问

追问 1为什么 Koa 里外层中间件在 await next() 之后改 ctx.body 还能生效?
参考回答

因为中间件只是改 ctx 上的值,并没有真正发响应。整条链的 Promise 完成之后 respond(ctx) 才读 ctx.body 写到 res,所以最后一次赋值算数。

追问 2ctx.request 和 ctx.req 有什么区别?
参考回答

ctx.req 是 Node 原生的 IncomingMessage,ctx.request 是 Koa 包的一层,提供 query、path、accepts() 这些便捷属性和方法。日常用 ctx.request,直接读原生流(比如自己解析上传)才碰 ctx.req。

追问 3中间件里在成功分支和 finally 里各调了一次 next(),会怎样?
参考回答

第二次调用 compose 会直接 reject,报 next() called multiple times。它靠记录上一次执行到的下标来判断,同一个位置再调就拦下。

追问 4测试时怎么不起端口就测 Koa 应用?
参考回答

app.callback() 返回的就是 (req, res) => {} 处理函数,supertest(app.callback()) 直接发请求,不占端口。

追问 5为什么每个请求都要新建一个 ctx,不能复用吗?
参考回答

ctx 上挂着这次请求的 body、state、status,并发请求共用一个就会互相串数据。每次 Object.create 一个新对象,原型指向 app.context,所以 app.context 上加的属性每个 ctx 都能读到。

# koa2简析结构

# 源码文件

30 秒速记

  • 核心就 lib/ 下四个文件:application.js / context.js / request.js / response.js
  • application.js = 入口:use 收中间件、listen 起服务、callback 组装 compose 并创建 ctx
  • context.js = ctx 的原型:onerror、throw,以及用 delegates 把 request / response 的属性代理过来
  • request.js / response.js = 对原生 req / res 的封装,ctx.query、ctx.body 的真正实现在这
  • 读源码路线:从 application.js 的 listen → callback → handleRequest 顺着往下看

Koa2 的源码核心只有 lib 目录下四个文件,application.js 是入口,另外三个分别管上下文、请求和响应。 application.js 负责收集中间件、创建 ctx、执行中间件链再统一响应;request.js 和 response.js 包了原生 req / res,比如 query 怎么解析、body 赋值后 Content-Type 怎么推断都在这里。context.js 是 ctx 的原型,它本身没多少逻辑,主要是把 request 和 response 上的常用属性代理出来,所以你能直接写 ctx.path、ctx.body。看源码我会从 application.js 的 listen 开始顺着调用往下读,比四个文件挨个看好懂得多。

├── lib
│   ├── application.js
│   ├── context.js
│   ├── request.js
│   └── response.js
└── package.json
@前端进阶之旅: 代码已经复制到剪贴板

这个就是 GitHub https://github.com/koajs/koa上开源的koa2源码的源文件结构,核心代码就是lib目录下的四个文件

  • application.js 是整个koa2 的入口文件,封装了context,request,response,以及最核心的中间件处理流程。
  • context.js 处理应用上下文,里面直接封装部分request.js和response.js的方法
  • request.js 处理http请求
  • response.js 处理http响应

面试官追问

追问 1ctx.body = 'hi' 这行赋值,真正处理逻辑在哪个文件?
参考回答

context.js 只是把 body 代理到 response,真正的 set body() 在 response.js 里,它会顺手把状态码设成 200、根据内容推断 Content-Type。

追问 2ctx.path 为什么能直接用,ctx 上明明没定义这个属性?
参考回答

context.js 用 delegates 库把 request.path 代理到了 ctx 上,读 ctx.path 实际读的是 ctx.request.path。哪些属性被代理了,看 context.js 底部那一串 .access() / .getter() 就清楚。

追问 3想给所有 ctx 加一个 ctx.success(data) 方法,改哪?
参考回答

不用改源码,挂到 app.context 上就行:app.context.success = function (data) { this.body = { code: 0, data } }。每个 ctx 的原型都是它。

追问 4请求经过中间件后一直没响应,要看源码定位,从哪个文件开始?
参考回答

从 application.js 的 handleRequest 开始,确认中间件链的 Promise 有没有完成、respond 有没有被调用。没完成说明有中间件卡住了,再回到业务代码找。

追问 5ctx.state 是干嘛的,在哪定义?
参考回答

在 application.js 的 createContext 里,每个请求初始化一个空对象,专门用来在中间件之间传数据,比如鉴权中间件把 ctx.state.user 存进去,后面的路由直接取。

# koa2特性

← 1.2 async await使用1.4 koa中间件开发与使用 →

fe